/**************************************************************************
** Qt Creator license header template
**   Special keywords: Programmer 2012/3/20 2012
**   Environment variables: 
**   To protect a percent sign, use '%'.
**************************************************************************/
#include <vcg/complex/algorithms/clean.h>
#include <vcg/complex/algorithms/inertia.h>

#include "meshmodel.h"

MeshModel::MeshModel()
{
}

void MeshModel::cleanMesh(QString& info/*out*/){
    CleanInfo ci;
    ci.dv = vcg::tri::Clean<MyTriMesh>::RemoveDuplicateVertex(mesh);

    ci.df = vcg::tri::Clean<MyTriMesh>::RemoveDegenerateFace(mesh);
    ci.df += vcg::tri::Clean<MyTriMesh>::RemoveFaceOutOfRangeArea<false>(mesh,0);

    ci.uv = vcg::tri::Clean<MyTriMesh>::RemoveUnreferencedVertex(mesh);

    vcg::tri::UpdateTopology<MyTriMesh>::FaceFace(mesh);
    vcg::tri::UpdateTopology<MyTriMesh>::VertexFace(mesh);

    ci.nmv = vcg::tri::Clean<MyTriMesh>::RemoveNonManifoldVertex(mesh);
    ci.nmf = vcg::tri::Clean<MyTriMesh>::RemoveNonManifoldFace(mesh);

    vcg::tri::Allocator<MyTriMesh>::CompactVertexVector(mesh);
    vcg::tri::Allocator<MyTriMesh>::CompactFaceVector(mesh);

    vcg::tri::UpdateTopology<MyTriMesh>::FaceFace(mesh);
    vcg::tri::UpdateTopology<MyTriMesh>::VertexFace(mesh);

    info = "Number of Duplicated Vertices removed: " + QString::number(ci.dv) +"\n" +
            "Number of Degenerated faces removed: " + QString::number(ci.df) +"\n" +
            "Number of Unreferenced Vertices removed: " + QString::number(ci.uv) +"\n" +
            "Number of Non-manifold Vertices removed: " + QString::number(ci.nmv) +"\n" +
            "Number of Non-manifold faces removed: " + QString::number(ci.nmf) +"\n";
}

void MeshModel::getMeshInfo(QString &infoText){
    MeshInfo mi;
    if (load_mask & vcg::tri::io::Mask::IOM_VERTNORMAL)
        mi.hasVNormal = true;
    else
        mi.hasVNormal = false;

    if (load_mask & vcg::tri::io::Mask::IOM_FACENORMAL)
        mi.hasFNormal = true;
    else
        mi.hasFNormal = false;

    if (load_mask & vcg::tri::io::Mask::IOM_VERTCOLOR)
        mi.hasVColor = true;
    else
        mi.hasVColor = false;

    if (load_mask & vcg::tri::io::Mask::IOM_FACECOLOR)
        mi.hasFColor = true;
    else
        mi.hasFColor = false;

    if( (load_mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD) ||
            (load_mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) )
        mi.hasTexture = true;
    else
        mi.hasTexture = false;

    // Number of vertices
    mi.vn = mesh.vn;

    // Number of faces
    mi.fn = mesh.fn;

    // Update topology (face-to-face)
    vcg::tri::UpdateTopology<MyTriMesh>::FaceFace(mesh);
    vcg::tri::UpdateTopology<MyTriMesh>::VertexFace(mesh);

    // IS MANIFOLD?
    mi.VManifold = vcg::tri::Clean<MyTriMesh>::CountNonManifoldVertexFF(mesh)==0;
    mi.FManifold = vcg::tri::Clean<MyTriMesh>::CountNonManifoldEdgeFF(mesh)==0;

    // COUNT EDGES
    vcg::tri::Clean<MyTriMesh>::CountEdges(mesh, mi.count_e, mi.boundary_e);

    // HOLES COUNT
    if(mi.VManifold && mi.FManifold)
    {
        mi.numholes = vcg::tri::Clean<MyTriMesh>::CountHoles(mesh);
    }

    // CONNECTED COMPONENTS
    mi.numcomponents = vcg::tri::Clean<MyTriMesh>::CountConnectedComponents(mesh);

    // ORIENTATION
    if (mi.VManifold && mi.FManifold)
        vcg::tri::Clean<MyTriMesh>::OrientCoherentlyMesh(mesh, mi.Oriented, mi.Orientable);
    else
    {
        mi.Oriented = false;
        mi.Orientable = false;
    }


    infoText="Number of vertices: " + QString::number(mi.vn) + "\n"+
                "Number of faces: " + QString::number(mi.fn) + "\n"+
                "Number of edges:" + QString::number(mi.count_e) + "\n" +
                "Number of internal edges: " + QString::number(mi.count_e - mi.boundary_e)+"\n"+
                "Number of boundary edges: " + QString::number(mi.boundary_e)+"\n"+
                "Number of holes/boundaries: "+ QString::number(mi.numholes)+"\n"+
                "Number of components: "+ QString::number(mi.numcomponents)+"\n";

        if (mi.hasVNormal)
            infoText += "Has Per-Vertex Normal: YES\n";
        else
            infoText += "Has Per-Vertex Normal: NO\n";

        if (mi.hasFNormal)
            infoText += "Has Per-Face Normal: YES\n";
        else
            infoText += "Has Per-Face Normal: NO\n";

        if (mi.hasVColor)
            infoText += "Has Per-Vertex Color: YES\n";
        else
            infoText += "Has Per-Vertex Color: NO\n";

        if (mi.hasFColor)
            infoText += "Has Per-Face Color: YES\n";
        else
            infoText += "Has Per-Face Color: NO\n";

        if (mi.hasTexture)
            infoText += "Has Texture information: YES\n";
        else
            infoText += "Has Texture information: NO\n";

        // Orientation
        if (!mi.VManifold && mi.FManifold)
        {
            infoText += "Orientable Mesh: NO\n";
            infoText += "Oriented Mesh: NO\n";
        }
        else
        {
            if (mi.Orientable)
                infoText += "Orientable Mesh: YES\n";
            else
                infoText += "Orientable Mesh: NO\n";

            if (mi.Oriented)
                infoText += "Oriented Mesh: YES\n";
            else
                infoText += "Oriented Mesh: NO\n";
        }

        // Manifold
        if (mi.VManifold && mi.FManifold )
            infoText += "Manifold: YES\n";
        else
            infoText += "Manifold: NO\n";

}
void MeshModel::loadMesh(QString& pathName,QString& msg)
{
    fullPathName = pathName;
    msg = pathName + " loaded successfully";

    vcg::tri::io::Importer<MyTriMesh>::LoadMask((pathName.toStdString()).c_str(),load_mask);
    int err = vcg::tri::io::Importer<MyTriMesh>::Open(
                mesh,
                (pathName.toStdString()).c_str());
    if(err != 0){
        msg = vcg::tri::io::Importer<MyTriMesh>::ErrorMsg(err);
    }

    vcg::tri::UpdateBounding<MyTriMesh>::Box(mesh);
    vcg::tri::UpdateNormals<MyTriMesh>::PerVertexNormalizedPerFace(mesh);
    vcg::tri::UpdateNormals<MyTriMesh>::PerFaceNormalized(mesh);

    glWrapMesh.m = &mesh;
    glWrapMesh.Update();
}

void MeshModel::render(RenderMode& mode)
{
    float d= 1.0f/mesh.bbox.Diag();
    vcg::glScale(d);
    glTranslate(-glWrapMesh.m->bbox.Center());
    //glWrapMesh.Draw<vcg::GLW::DMSmooth,vcg::GLW::CMNone,vcg::GLW::TMNone>();
    //glWrapMesh.Draw<vcg::GLW::DMFlatWire, vcg::GLW::CMNone,vcg::GLW::TMNone> ();

    switch(mode)
    {
    case SMOOTH:
        glWrapMesh.Draw<vcg::GLW::DMSmooth,   vcg::GLW::CMNone,vcg::GLW::TMNone> ();
        break;
    case POINTS:
        glWrapMesh.Draw<vcg::GLW::DMPoints,   vcg::GLW::CMNone,vcg::GLW::TMNone> ();
        break;
    case WIRE:
        glWrapMesh.Draw<vcg::GLW::DMWire,     vcg::GLW::CMNone,vcg::GLW::TMNone> ();
        break;
    case FLATWIRE:
        glWrapMesh.Draw<vcg::GLW::DMFlatWire, vcg::GLW::CMNone,vcg::GLW::TMNone> ();
        break;
    case HIDDEN:
        glWrapMesh.Draw<vcg::GLW::DMHidden,   vcg::GLW::CMNone,vcg::GLW::TMNone> ();
        break;
    case FLAT:
        glWrapMesh.Draw<vcg::GLW::DMFlat,     vcg::GLW::CMNone,vcg::GLW::TMNone> ();
        break;
    default:
        break;
    }
}
